<?php
/**
 * Created by PhpStorm.
 * User: longli
 * VX: isa1589518286
 * Date: 2020/04/14
 * Time: 11:34
 * @link http://www.lmterp.cn
 */

namespace app\common\model;

use app\common\library\Tools;
use Exception;
use think\Collection;
use think\exception\DbException;
use think\Model;
use think\model\relation\HasMany;

/**
 * 订单模型
 * Class Order
 * @package app\common\model
 */
class Orders extends BaseModel
{
    protected $pk = 'order_id';

    protected $autoWriteTimestamp = 'datetime';

    // 设置 json 字段
    protected $json = ['ext_json'];

    protected $insert = ['create_by', 'update_by'];

    protected $update = ['update_by'];

    /**
     * 未标记
     * @var int
     */
    const FLAG_SENT_NO = 0;

    /**
     * 已标记
     * @var int
     */
    const FLAG_SENT_YES = 1;

    /**
     * 不需要标记
     * @var int
     */
    const FLAG_SENT_NO_NEED = 2;

    /**
     * 部分标记
     * @var int
     */
    const FLAG_SENT_PART = 3;

    public static $ORDER_FLAG = [
        self::FLAG_SENT_NO      => '未标记',
        self::FLAG_SENT_YES     => '已标记',
        self::FLAG_SENT_NO_NEED => '不需要标记',
        self::FLAG_SENT_PART    => '部分标记',
    ];

    /**
     * 待处理
     * @var int
     */
    const ORDER_WAIT = 0;

    /**
     * 已分仓
     * @var int
     */
    const ORDER_WAREHOUSE = 10;

    /**
     * 占用库存
     * @var int
     */
    const ORDER_LOCK = 20;

    /**
     * 释放库存
     * @var int
     */
    const ORDER_UNLOCK = 30;

    /**
     * 申报中
     * @var int
     */
    const ORDER_DECLARE_ING = 40;

    /**
     * 申报成功
     * @var int
     */
    const ORDER_DECLARE_SUCC = 50;

    /**
     * 申报失败
     * @var int
     */
    const ORDER_DECLARE_ERROR = 60;

    /**
     * 获取面单失败
     * @var int
     */
    const ORDER_LABEL_ERROR = 70;

    /**
     * 缺货
     * @var int
     */
    const ORDER_LACK = 80;

    /**
     * 待采购
     * @var int
     */
    const ORDER_WAIT_PUR = 90;

    /**
     * 采购中
     * @var int
     */
    const ORDER_WAIT_PUR_ING = 100;

    /**
     * 拣货中
     * @var int
     */
    const ORDER_PACKAGE = 110;

    /**
     * 待出货
     * @var int
     */
    const ORDER_WAIT_OUT = 120;

    /**
     * 已发货
     * @var int
     */
    const ORDER_SEND = 130;

    /**
     * 全部退款
     * @var int
     */
    const ORDER_RETURN = 140;

    /**
     * 部分退款
     * @var int
     */
    const ORDER_RETURN_PART = 150;

    /**
     * 已拒付
     * @var int
     */
    const ORDER_REJECT = 160;

    /**
     * 风险
     * @var int
     */
    const ORDER_RISK = 170;

    /**
     * 刷单
     * @var int
     */
    const ORDER_FALSE = 180;

    /**
     * 取消订单
     * @var int
     */
    const ORDER_CANCEL = 190;

    /**
     * 异常
     * @var int
     */
    const ORDER_EXCEPTION = 200;

    /**
     * 价格低
     * @var int
     */
    const ORDER_PRICE_LOW = 210;

    /**
     * 订单完成
     * @var int
     */
    const ORDER_SUCCESS = 220;

    public static $ORDER_STATUS = [
        self::ORDER_WAIT          => '待处理',
        self::ORDER_WAREHOUSE     => '已分仓',
        self::ORDER_LOCK          => '占用库存',
        self::ORDER_UNLOCK        => '释放库存',
        self::ORDER_DECLARE_ING   => '申报中',
        self::ORDER_DECLARE_SUCC  => '申报成功',
        self::ORDER_DECLARE_ERROR => '申报失败',
        self::ORDER_LABEL_ERROR   => '获取面单失败',
        self::ORDER_LACK          => '缺货',
        self::ORDER_WAIT_PUR      => '待采购',
        self::ORDER_WAIT_PUR_ING  => '采购中',
        self::ORDER_PACKAGE       => '拣货中',
        self::ORDER_WAIT_OUT      => '待出货',
        self::ORDER_SEND          => '已发货',
        self::ORDER_RETURN        => '全部退款',
        self::ORDER_RETURN_PART   => '部分退款',
        self::ORDER_REJECT        => '已拒付',
        self::ORDER_RISK          => '风险',
        self::ORDER_FALSE         => '刷单',
        self::ORDER_CANCEL        => '取消订单',
        self::ORDER_EXCEPTION     => '异常',
        self::ORDER_PRICE_LOW     => '价格低',
        self::ORDER_SUCCESS       => '订单完成',
    ];

    /**
     * 未发货
     * @var int
     */
    const SEND_WAIT = 0;

    /**
     * 更换渠道
     * @var int
     */
    const SEND_UPDATE = 10;

    /**
     * 部分发货
     * @var int
     */
    const SEND_PART = 20;

    /**
     * 已发货
     * @var int
     */
    const SEND_ALL = 30;

    /**
     * 超时未发货
     * @var int
     */
    const SEND_WAIT_TIMEOUT = 40;

    /**
     * 退货中
     * @var int
     */
    const SEND_RETURN_ING = 50;

    /**
     * 全部退货
     * @var int
     */
    const SEND_RETURN_ALL = 60;

    /**
     * 部分退货
     * @var int
     */
    const SEND_RETURN_PART = 70;

    /**
     * 无需发货
     * @var int
     */
    const SEND_NO_NEED = 80;

    /**
     * 运输超时
     * @var int
     */
    const SEND_TIMEOUT = 90;

    /**
     * 派送中
     * @var int
     */
    const SEND_PICKUP = 100;

    /**
     * 派送失败
     * @var int
     */
    const SEND_UNRECV = 110;

    /**
     * 物流异常
     * @var int
     */
    const SEND_EXCEPTION = 120;

    /**
     * 已签收
     * @var int
     */
    const SEND_RECEIVE = 130;

    public static $SEND_STATUS = [
        self::SEND_WAIT         => '未发货',
        self::SEND_UPDATE       => '更换渠道',
        self::SEND_PART         => '部分发货',
        self::SEND_ALL          => '已发货',
        self::SEND_WAIT_TIMEOUT => '超时未发货',
        self::SEND_RETURN_ING   => '退货中',
        self::SEND_RETURN_ALL   => '全部退货',
        self::SEND_RETURN_PART  => '部分退货',
        self::SEND_NO_NEED      => '无需发货',
        self::SEND_TIMEOUT      => '运输超时',
        self::SEND_PICKUP       => '派送中',
        self::SEND_UNRECV       => '派送失败',
        self::SEND_EXCEPTION    => '物流异常',
        self::SEND_RECEIVE      => '已签收',
    ];

    /**
     * 未标记
     */
    const FLAG_N = 0;

    /**
     * 已标记
     */
    const FLAG_Y = 1;

    /**
     * 不需要标记
     */
    const FLAG_NN = 2;

    /**
     * 部分标记
     */
    const FLAG_S = 3;

    public static $FLAG_STATUS = [
        self::FLAG_N   => '未标记',
        self::FLAG_Y   => '已标记',
        self::FLAG_NN  => '不需要标记',
        self::FLAG_S   => '部分标记',
    ];


    /**
     * 已打印
     */
    const PRINT_Y = 1;

    /**
     * 未打印
     */
    const PRINT_N = 0;

    public static $PRINT_STATUS = [
        self::PRINT_N => '未打印',
        self::PRINT_Y => '已打印',
    ];

    protected function getIsPrintAttr($value)
    {
        return isset(self::$PRINT_STATUS[$value])
            ? self::$PRINT_STATUS[$value]
            : $value;
    }

    protected function getOrderStatusAttr($value)
    {
        return isset(self::$ORDER_STATUS[$value])
            ? self::$ORDER_STATUS[$value]
            : $value;
    }

    protected function getSendStatusAttr($value)
    {
        return isset(self::$SEND_STATUS[$value])
            ? self::$SEND_STATUS[$value]
            : $value;
    }

    protected function getIsFlagSentAttr($value)
    {
        return isset(self::$FLAG_STATUS[$value])
            ? self::$FLAG_STATUS[$value]
            : $value;
    }

    /**
     * 一对多关联订单详情
     * @return HasMany
     * @date 2020/04/14
     * @author longli
     */
    public function detail()
    {
        return $this->hasMany(OrdersDetail::class, 'order_id', 'order_id');
    }

    /**
     * 关联订单追踪号
     * @return \think\model\relation\HasOne
     * @date 2021/04/05
     * @author longli
     */
    public function track()
    {
        return $this->hasOne(ChannelOrders::class, 'order_id', 'order_id')->where("is_cancel", "=", ChannelOrders::IS_NO);
    }

    /**
     * 关联退货单
     * @return \think\model\relation\HasOne
     * @date 2021/04/05
     * @author longli
     */
    public function ren()
    {
        return $this->hasOne(OrdersReturn::class, 'order_id', 'order_id');
    }

    /**
     * 关联管理员
     * @return \think\model\relation\BelongsTo
     * @date 2021/04/05
     * @author longli
     */
    public function admin()
    {
        return $this->belongsTo(Admin::class, "create_by", "id");
    }

    /**
     * 关联币种
     * @return \think\model\relation\BelongsTo
     * @date 2021/04/05
     * @author longli
     */
    public function currcode()
    {
        return $this->belongsTo(SysCountries::class, 'currency', 'currency_code');
    }

    /**
     * 关联仓库
     * @return \think\model\relation\BelongsTo
     * @date 2021/03/03
     * @author longli
     */
    public function warehouse()
    {
        return $this->belongsTo(Warehouse::class);
    }

    /**
     * 多对一订单关联账号
     * @date 2020/08/26
     * @author longli
     */
    public function account()
    {
        return $this->belongsTo(Account::class);
    }

    /**
     * 通过 id 获取订单
     * @param int|int[] $ids 单个或多个订单
     * @return array|Collection
     * @date 2020/04/14
     * @author longli
     */
    public static function getListById($ids)
    {
        if(!is_array($ids)) $ids = [$ids];
        $orders = [];
        try
        {
            $orders = static::whereIn('order_id', $ids)->select();
        }
        catch(DbException $exception){}
        return count($ids) == 1 && !empty($orders) ? $orders[0] : $orders;
    }

    /**
     * 通过内部订单号获取订单
     * @param string|array $orderSn
     * @return array|Model|null
     * @date 2020/04/16
     * @author longli
     */
    public static function getBySn($orderSn)
    {
        if(!is_array($orderSn)) $orderSn = [$orderSn];
        $orders = [];
        try
        {
            $orders =  static::whereIn("order_sn", $orderSn)->select();
        }catch(DbException $e){}
        return count($orderSn) == 1 && !empty($orders) ? $orders[0] : $orders;
    }

    /**
     * 通过平台订单号获取订单
     * @param string|array $orderNo 平台订单号
     * @param string $platform 平台
     * @return array|string|Collection
     * @date 2020/04/16
     * @author longli
     */
    public static function getByNo($orderNo, $platform = '')
    {
        if(!is_array($orderNo)) $orderNo = [$orderNo];
        $where = ["order_no" =>  $orderNo];
        if(!empty($platform)) $where['order_source'] = $platform;
        $orders = [];
        try
        {
            $orders = static::where($where)->select();
        }catch(DbException $e){}
        if($orders->isEmpty()) return [];
        return count($orderNo) == 1 && !empty($orders) ? $orders[0] : $orders;
    }

    /**
     * 通过内部订单号/平台订单号获取订单
     * @param string $sn 内部订单号/平台订单号
     * @return Orders
     * @date 2021/08/12
     * @author longli
     */
    public static function getSnNo($sn)
    {
        return static::whereRaw("order_sn=? OR order_no=?", [$sn, $sn])->find();
    }

    /**
     * 订单号获取订单
     * @param string $tsn 内部订单号/平台订单号/追踪号
     * @return static
     * @date 2021/02/22
     * @author longli
     */
    public static function getByTsn($tsn)
    {
        $tsn = trim($tsn);
        return static::whereRaw("order_sn=? OR order_no=? OR track_num=?", [$tsn, $tsn, $tsn])->find();
    }

    /**
     * 检查订单是否存在
     * @param string $sn 平台订单号/内部订单号
     * @return bool
     * @date 2021/08/12
     * @author longli
     */
    public static function hasSn($sn)
    {
        return !!static::whereRaw("order_sn=? OR order_no=?", [$sn, $sn])->count();
    }

    /**
     * 获取买家名称
     * @param Orders|int $orders 订单订单id
     * @return string
     * @date 2020/09/04
     * @author longli
     */
    public static function getBuyerName($orders)
    {
        if(is_numeric($orders)) $orders = static::get($orders);
        return $orders->consignee ? : ($orders->buyer_first_name . ' ' . $orders->buyer_last_name);
    }

    /**
     * 获取买家电话
     * @param Orders|int $orders 订单订单id
     * @return string
     * @date 2020/11/24
     * @author longli
     */
    public static function getBuyerPhone($orders)
    {
        if(is_numeric($orders)) $orders = static::get($orders);
        return $orders->buyer_phone ?: $orders->buyer_mobile;
    }

    /**
     * 订单是否全部退货
     * @return bool
     * @date 2021/03/04
     * @author longli
     */
    public function isReturnAll()
    {
        foreach($this->detail as $detail)
        {
            if($detail->return_qty != $detail->qty) return false;
        }
        return true;
    }

    /**
     * 通过订单id批量修改数据
     * @param int|int[] $ids 订单id
     * @param array $data 值
     * @return bool
     * @date 2020/09/03
     * @author longli
     */
    public static function editByOrderId($ids, $data)
    {
        try
        {
            foreach(static::where("order_id", "in", $ids)->select() as $order)
            {
                if(!empty($data['logistics_name']) && !empty($data['channel_id']))
                {
                    $data['label_url'] = '';
                    $data['is_print'] = self::PRINT_N;
                    if($order->getData('send_status') != self::SEND_WAIT) $data['send_status'] = self::SEND_UPDATE;
                    $data['track_num'] = '';
                    $data['logistics_price'] = 0;
                }
                if(!empty($data['channel_id']))
                {
                    $data['shipping_method'] = Channel::get($data['channel_id'])->channel_name;
                }
                if(!empty($data['send_status']) && $data['send_status'] == Orders::SEND_ALL)
                {
                    $data['sent_time'] = Tools::now();
                }
                $order->save($data);
            }
            return true;
        }catch(Exception $e)
        {
            return false;
        }
    }

    /**
     * 是否 FBA 订单
     * @return bool
     * @date 2021/03/10
     * @author longli
     */
    public function isFBA()
    {
        return trim($this->track_num) == 'FBA';
    }

    /**
     * 计算订单净重
     * @return int
     * @date 2021/06/22
     * @author longli
     */
    public function getWeight()
    {
        if($this->weight > 0) return $this->weight;
        $temp = $this->detail->toArray();
        $skus = array_combine(array_column($temp, 'sku'), array_column($temp, 'qty'));
        $this->weight = \app\common\service\product\ProductService::getInstance()->getTotalWeight($skus);
        $this->save();
        return $this->weight;
    }

    /**
     * 计算订单
     * @date 2021/03/11
     * @author longli
     */
    public function computeOrder()
    {
        $exService = \app\common\service\system\SystemService::getInstance();
        $detail = $this->detail->toArray();
        $this->weight = $this->getWeight(); // 计算订单重量
        $this->total_qty = array_sum(array_column($detail, 'qty')); // 计算订单总数
        $this->order_price = array_sum(array_column($detail, 'total_price')); // 计算订单商品总价
        $this->discount_amount = $this->coupon_price + array_sum(array_column($detail, 'discount')); // 订单优惠金额
        // 计算订单总价
        $this->total_price = $this->order_price + $this->shipping_price + $this->surcharge_price - $this->discount_amount;
        $this->total_price_rmb = $exService->exchangeRate($this->currency, $this->total_price); // 订单转成人民币
        // 计算利润 @todo
        // $this->profit = 0;
        if(CsBlacklist::inBlackBox($this)) $this->order_status = Orders::ORDER_RISK; // 检查是否为风险订单
        $this->save();
    }

    /**
     * 订单是否包含指定 sku
     * @param string|string[] $sku sku
     * @return bool
     * @date 2021/06/28
     * @author longli
     */
    public function hasSku($sku)
    {
        if(!is_array($sku)) $sku = explode(',', $sku);
        $detail = $this->detail->toArray();
        $dsku = array_column($detail, 'sku');
        return \app\common\library\Tools::containArray($dsku, $sku, false);
    }

    /**
     * 更新面单打印状态
     * @return bool
     * @date 2021/07/20
     * @author longli
     */
    public function printLabel()
    {
        $this->is_print = self::IS_YES;
        if(in_array($this->getData('order_status'), [self::ORDER_DECLARE_SUCC]))
            $this->order_status = self::ORDER_PACKAGE;
        return $this->save();
    }
}